﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ServiceModel.Channels;
using System.Xml;
using System.Xml.Linq;

namespace WcfContrib.Helpers
{
    /// <summary>
    /// A helper class for dealing with messages
    /// </summary>
    public static class MessageHelper
    {
        /// <summary>
        /// Tries to get the messages relates-to id.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="guid">The matched relates-to id.</param>
        /// <returns>Whether the relates-to id was matched or not</returns>
        public static bool TryGetRelatesToId(this Message message, out Guid guid)
        {
            return TryGetUniqueId(message.Headers.RelatesTo, out guid);
        }

        /// <summary>
        /// Tries to get the messages relates-to id.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="guid">The matched relates-to id.</param>
        /// <returns>Whether the relates-to id was matched or not</returns>
        public static bool TryGetMessageId(this Message message, out Guid guid)
        {
            return TryGetUniqueId(message.Headers.MessageId, out guid);
        }

        /// <summary>
        /// Tries to get the guid id from the uniqueid.
        /// </summary>
        /// <param name="uniqueId">The unique id.</param>
        /// <param name="guid">The matched guid id.</param>
        /// <returns>Whether the guid id was matched or not</returns>
        public static bool TryGetUniqueId(UniqueId uniqueId, out Guid guid)
        {
            guid = Guid.Empty;

            return (uniqueId != null && uniqueId.TryGetGuid(out guid));
        }

        /// <summary>
        /// Gets the message relates-to id.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns>The message relates-to id</returns>
        public static Guid? GetRelatesToId(this Message message)
        {
            return GetUniqueId(message.Headers.RelatesTo);
        }

        /// <summary>
        /// Gets the message id.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns>The message id</returns>
        public static Guid? GetMessageId(this Message message)
        {
            return GetUniqueId(message.Headers.MessageId);
        }

        /// <summary>
        /// Gets the guid id from the uniqueid.
        /// </summary>
        /// <param name="uniqueId">The unique id.</param>
        /// <returns>The guid id from the uniqueid</returns>
        public static Guid? GetUniqueId(UniqueId uniqueId)
        {
            Guid? result = null;

            if (uniqueId != null)
            {
                Guid guid;
                if (uniqueId.TryGetGuid(out guid))
                {
                    result = guid;
                }
            }

            return result;
        }

        /// <summary>
        /// Reads the message to string.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns></returns>
        public static string ReadToString(this Message message)
        {
            using (MemoryStream ms = CreateMessageStream(message))
            using (StreamReader reader = new StreamReader(ms))
            {
                return reader.ReadToEnd();
            }
        }

        /// <summary>
        /// Reads the message to XElement.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns></returns>
        public static XElement ReadToXElement(this Message message)
        {
            using (MemoryStream ms = CreateMessageStream(message))
            using (XmlReader reader = XmlReader.Create(ms))
            {
                return XElement.Load(reader);
            }
        }

        static MemoryStream CreateMessageStream(Message message)
        {
            MemoryStream ms = new MemoryStream();

            using (XmlWriter writer = XmlWriter.Create(ms))
            {
                message.WriteMessage(writer);
                writer.Flush();
            }

            ms.Seek(0L, SeekOrigin.Begin);

            return ms;
        }

        /// <summary>
        /// Checks whether a string URI contains a segment.
        /// </summary>
        /// <param name="uri">The URI.</param>
        /// <param name="segment"> The segment.</param>
        /// <returns></returns>
        public static bool UriContainsSegment(string uri, string segment)
        {
            return !string.IsNullOrEmpty(uri)
                && (uri.EndsWith("/" + segment) || uri.Contains("/" + segment + "/"));
        }
    }
}
